package fr.umlv.m2.jee.spij.service.project.impl;

import fr.umlv.m2.jee.spij.persistence.actor.StudentProject;
import fr.umlv.m2.jee.spij.persistence.actor.TeacherProject;
import fr.umlv.m2.jee.spij.persistence.actor.dao.HibernateStudentProjectDAO;
import fr.umlv.m2.jee.spij.persistence.actor.dao.HibernateTeacherProjectDAO;
import fr.umlv.m2.jee.spij.persistence.education.Project;
import fr.umlv.m2.jee.spij.persistence.education.Unit;
import fr.umlv.m2.jee.spij.persistence.education.dao.HibernateProjectDAO;
import fr.umlv.m2.jee.spij.persistence.education.dao.HibernateUnitDAO;
import fr.umlv.m2.jee.spij.service.ldap.authentification.DisplayActor;
import fr.umlv.m2.jee.spij.service.project.DisplayProject;
import fr.umlv.m2.jee.spij.service.project.IDisplayProjectService;
import org.joda.time.DateTime;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.binding.message.MessageBuilder;
import org.springframework.binding.message.MessageContext;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * @author thomas magny
 * @author mathieu mazzolini
 */
@Service("defaultDisplayProjectService")
public class DefaultDisplayProjectService implements IDisplayProjectService {

    @Autowired
    private HibernateUnitDAO unitDAO;

    @Autowired
    private HibernateStudentProjectDAO studentProjectDAO;

    @Autowired
    private HibernateTeacherProjectDAO teacherProjectDAO;

    @Autowired
    private HibernateProjectDAO projectDAO;

    public DefaultDisplayProjectService() {
    }

    /*
     * (non-Javadoc)
     * 
     * @see fr.umlv.m2.jee.spij.service.project.IDisplayProjectService#
     * getAllDisplayProject(long,
     * org.springframework.binding.message.MessageContext)
     */

    @Override
    @Transactional(readOnly = true)
    public List<DisplayProject> getAllDisplayProject(final long unitId, MessageContext context) {
        final Unit unit = unitDAO.findById(unitId);
        final List<Project> projects = unit.getProjects();
        final List<DisplayProject> displayProjects = new ArrayList<DisplayProject>();

        if (projects == null) {
            context.addMessage(new MessageBuilder().info().code("projects.empty").build());
        } else {
            for (Project project : projects) {
                DisplayProject displayProject = new DisplayProject(project);
                if (unit != null)
                    displayProject.setUnitName(unit.getName());
                displayProjects.add(displayProject);
            }
        }

        return displayProjects;
    }

    /*
     * (non-Javadoc)
     * 
     * @see fr.umlv.m2.jee.spij.service.project.IDisplayProjectService#
     * getAllDisplayProjectPerUser(long,
     * fr.umlv.m2.jee.spij.service.ldap.authentification.DisplayActor,
     * org.springframework.binding.message.MessageContext)
     */

    @Override
    @Transactional(readOnly = true)
    public List<DisplayProject> getAllDisplayProjectPerUser(final long unitId, DisplayActor currentUser, MessageContext context) {
        if (currentUser.isTeacher() || currentUser.isStudent()) {
            Unit unit = unitDAO.findById(unitId);
            final List<Project> Projects = projectDAO.findByLdapActorAndUnitId(unitId, currentUser.getLogin(), currentUser.getType());
            final List<DisplayProject> displayProjects = new ArrayList<DisplayProject>(Projects.size());

            if (Projects.isEmpty()) {
                context.addMessage(new MessageBuilder().error().code("projects.empty").build());
            } else {
                for (Project project : Projects) {
                    DisplayProject displayProject = new DisplayProject(project);
                    if (unit != null)
                        displayProject.setUnitName(unit.getName());
                    displayProjects.add(displayProject);
                }
            }
            return displayProjects;
        }

        return getAllDisplayProject(unitId, context);
    }

    /*
     * (non-Javadoc)
     * 
     * @see
     * fr.umlv.m2.jee.spij.service.project.IDisplayProjectService#getProjectById
     * (long, org.springframework.binding.message.MessageContext)
     */

    @Override
    @Transactional(readOnly = true)
    public DisplayProject getProjectById(long id, MessageContext context) {
        Project project = projectDAO.findById(id);
        DisplayProject displayProject = new DisplayProject(project);

        if (project == null) {
            context.addMessage(new MessageBuilder().error().code("project.empty").build());
        } else {
            if (project.getUnit() != null) {
                displayProject.setUnitName(unitDAO.findById(project.getUnit()).getName());
            }
        }
        return displayProject;
    }

    /*
     * (non-Javadoc)
     * 
     * @see
     * fr.umlv.m2.jee.spij.service.project.IDisplayProjectService#createProject
     * (fr.umlv.m2.jee.spij.service.project.DisplayProject, long,
     * org.springframework.binding.message.MessageContext)
     */

    @Override
    @Transactional(readOnly = false)
    public boolean createProject(DisplayProject displayProject, long unitId, MessageContext context) {
        Project project = new Project();
        project.setUnit(unitId);
        project.setSubject(displayProject.getSubject());
        project.setContain(displayProject.getContain());
        project.setLinkSupport(displayProject.getLinkSupport());

        if (displayProject.getWeight() <= 0) {
            context.addMessage(new MessageBuilder().error().code("project.weight.positive").build());
            return false;
        }
        project.setWeight(displayProject.getWeight());

        final Date deadLineDate = displayProject.getDeadLineDate();
        final Date deadLineHour = displayProject.getDeadLineHour();
        DateTime deadLine = new DateTime(deadLineDate.getTime());
        deadLine = deadLine.plus(deadLineHour.getTime());
        project.setDeadLine(deadLine);

        final Date presentationDate = displayProject.getPresentationDate();
        final Date presentationHour = displayProject.getPresentationHour();
        if (presentationDate != null && presentationHour != null) {
            DateTime presentation = new DateTime(presentationDate.getTime());
            presentation = presentation.plus(presentationHour.getTime());
            if (presentation.isBefore(deadLine)) {
                context.addMessage(new MessageBuilder().error().code("project.presentation.isBefore.deadLine").build());
                return false;
            }
            project.setPresentation(presentation);
        } else if (presentationDate != null) {
            context.addMessage(new MessageBuilder().error().code("project.presentation.incomplete").build());
            return false;
        } else if (presentationHour != null) {
            context.addMessage(new MessageBuilder().error().code("project.presentation.incomplete").build());
            return false;
        }

        projectDAO.persist(project);
        return true;
    }

    /*
     * (non-Javadoc)
     * 
     * @see
     * fr.umlv.m2.jee.spij.service.project.IDisplayProjectService#updateProjectById
     * (fr.umlv.m2.jee.spij.service.project.DisplayProject,
     * org.springframework.binding.message.MessageContext)
     */

    @Override
    @Transactional(readOnly = false)
    public boolean updateProjectById(DisplayProject modifiedProject, MessageContext context) {
        Project project = projectDAO.findById(modifiedProject.getId());
        boolean hasBeenModified = false;

        if (project != null) {
            if (!project.getSubject().equals(modifiedProject.getSubject())) {
                hasBeenModified = true;
                project.setSubject(modifiedProject.getSubject());
            }
            if (!project.getContain().equals(modifiedProject.getContain())) {
                hasBeenModified = true;
                project.setContain(modifiedProject.getContain());
            }
            if (!project.getLinkSupport().equals(modifiedProject.getLinkSupport())) {
                hasBeenModified = true;
                project.setLinkSupport(modifiedProject.getLinkSupport());
            }
            if (project.getWeight() != modifiedProject.getWeight()) {
                if (modifiedProject.getWeight() <= 0) {
                    context.addMessage(new MessageBuilder().error().code("project.weight.positive").build());
                    return false;
                }
                hasBeenModified = true;
                project.setWeight(modifiedProject.getWeight());
            }

            //Deadline update
            Date deadLineDate = modifiedProject.getDeadLineDate();
            Date deadLineHour = modifiedProject.getDeadLineHour();
            DateTime deadLine = new DateTime(deadLineDate.getTime());
            deadLine = deadLine.plus(deadLineHour.getTime());

            DateTime previousDeadLine = project.getDeadLine();

            //Presentation update
            final Date presentationDate = modifiedProject.getPresentationDate();
            final Date presentationHour = modifiedProject.getPresentationHour();
            DateTime previousPresentation = project.getPresentation();

            if (presentationDate != null && presentationHour != null) {
                DateTime presentation = new DateTime(presentationDate.getTime());
                presentation = presentation.plus(presentationHour.getTime());
                if (presentation.isBefore(deadLine)) {
                    context.addMessage(new MessageBuilder().error().code("project.presentation.isBefore.deadLine").build());
                    return false;
                }
                if (!presentation.equals(previousPresentation)) {
                    hasBeenModified = true;
                    project.setPresentation(presentation);
                }
            } else if (presentationDate != null) {
                context.addMessage(new MessageBuilder().error().code("project.presentation.incomplete").build());
                return false;
            } else if (presentationHour != null) {
                context.addMessage(new MessageBuilder().error().code("project.presentation.incomplete").build());
                return false;
            } else {
                if (previousPresentation != null) {
                    hasBeenModified = true;
                    project.setPresentation(null);
                }
            }

            if (!previousDeadLine.equals(deadLine)) {
                hasBeenModified = true;
                project.setDeadLine(deadLine);
            }

            projectDAO.merge(project);
        }

        if (!hasBeenModified) {
            context.addMessage(new MessageBuilder().error().code("updateProjectFail").build());
        }

        return hasBeenModified;
    }

    /*
     * (non-Javadoc)
     * 
     * @see
     * fr.umlv.m2.jee.spij.service.project.IDisplayProjectService#deleteProjectById
     * (long, org.springframework.binding.message.MessageContext)
     */

    @Override
    @Transactional(readOnly = false)
    public boolean deleteProjectById(long id, MessageContext context) {
        Project project = projectDAO.findById(id);
        List<StudentProject> students = project.getStudents();
        for (StudentProject studentProject : students) {
            studentProjectDAO.remove(studentProject);
            studentProjectDAO.flush();
        }
        List<TeacherProject> teachers = project.getTeachers();
        for (TeacherProject teacherProject : teachers) {
            teacherProjectDAO.remove(teacherProject);
            teacherProjectDAO.flush();
        }

        projectDAO.remove(project);
        projectDAO.flush();
        return true;
    }
}
